package com.samtech.commons;

import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.Map;

import org.springframework.util.Assert;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.type.TypeFactory;

/**
 * Json工具类
 * @author Smaple
 */
public final class JsonUtils {
	
	private JsonUtils() {}
	
	private static ObjectMapper basicPbjectMapper;
	
	private static ObjectMapper notNullobjectMapper;
	
	static {
		basicPbjectMapper = new ObjectMapper().configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		notNullobjectMapper = new ObjectMapper()
				.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
				.setSerializationInclusion(Include.NON_NULL);
	}
	
	/**
	 * 获取ObjectMapper对象
	 * @param ignoreNull 是否忽略字段中的null，若为true,则字段中的null不参与序列化
	 * @return
	 */
	private static ObjectMapper choseObjectMapper(boolean ignoreNull) {
		if (ignoreNull) {
			return notNullobjectMapper;
		} 
		return basicPbjectMapper;
	}
	
	/**
	 * 对象序列化为字符串,若字段为空，则显示null<p>
	 * 如：</br>
	 * {"orderId":"007","realName":"Swy", <b>"toAccType"=null </b>}
	 * @param object 需要转换的对象
	 * @return 对象对应的字符串
	 * @throws Exception
	 */
	public static String obj2Jsonstr(Object object) throws Exception {
		return obj2Jsonstr(object, false);
	}
	
	/**
	 * 对象序列化为字符串,可控制字段为空时的处理
	 * @param object 需要转换的对象
	 * @param ignoreNull 是否忽略字段中的null，若为true,则字段中的null不参与序列化
	 * @return 对象对应的字符串
	 * @throws Exception
	 */
	public static String obj2Jsonstr(Object object, boolean ignoreNull) throws Exception {
		ObjectMapper objectMapper = choseObjectMapper(ignoreNull);
		return objectMapper.writeValueAsString(object);
	}
	
	/**
	 * 将json字符串转换为javabean对象
	 * @param jsonstr json字符串
	 * @param valueType javabean对象的class
	 * @return 转换后的javabean
	 * @throws Exception
	 */
	public static<T> T jsonstr2Obj(String jsonstr, Class<T> valueType) throws Exception {
		return basicPbjectMapper.readValue(jsonstr, valueType);
	}
	
	/**
	 * 将json字符串转换成javabean对象，这个对象时一个包含了泛型的对象。
	 * @param jsonstr json字符串
	 * @param type 类型 传值如： new TypeReference&ltTest&ltMchIn&gt&gt(){},那么将对象转换成Test&ltMchIn&gt 
	 * @return 转换后的javabean
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static<T> T jsonstr2Obj(String jsonstr, TypeReference<T> type) throws Exception {
		return (T)basicPbjectMapper.readValue(jsonstr, type);
	}
	
	
	/**
	 * 获取json字符串中指定node名称（属性名称）对应的值
	 * @param jsonStr json字符串
	 * @param nodeName node名称，即属性名称
	 * @return 如果属性不存在则返回null,否则返回对应的属性值
	 * @throws Exception
	 */
	public static String getNodeValue(String jsonStr, String nodeName) throws Exception {
		JsonNode jsonNode = basicPbjectMapper.readTree(jsonStr);
		JsonNode node = jsonNode.get(nodeName);
		if (node == null) {
			return null;
		} 
		return node.asText();
	}
	
	/**
	 * 向指定的json字符串中添加node
	 * @param jsonStr 原json字符串
	 * @param nodes 需要添加的nodes
	 * @return 新的json字符串
	 * @throws Exception
	 */
	public static String createNodes(String jsonStr, Map<String, String> nodes) throws Exception {
		ObjectMapper objectMapper = choseObjectMapper(false);
		JsonNode jsonNode = objectMapper.readTree(jsonStr);
		Iterator<String> keys = jsonNode.fieldNames();
		ObjectNode node = objectMapper.createObjectNode();
		while(keys.hasNext()){  
			String fieldName = keys.next();  
			node.set(fieldName, jsonNode.get(fieldName));
		}
		for (Map.Entry<String, String> entry : nodes.entrySet()) {
			node.put(entry.getKey(), entry.getValue());
		}
		return objectMapper.writeValueAsString(node);
	}
	
	public static JsonNode parseToNode(String jsonStr) throws IOException {
		ObjectMapper objectMapper = choseObjectMapper(false);
		JsonNode jsonNode = objectMapper.readTree(jsonStr);
		return jsonNode;
	}
	
	/**
	 * 将对象转换为JSON流
	 * 
	 * @param writer
	 *            Writer
	 * @param value
	 *            对象
	 */
	public static void writeValue(Writer writer, Object value) {
		Assert.notNull(writer);
		Assert.notNull(value);

		try {
			notNullobjectMapper.writeValue(writer, value);
		} catch (JsonGenerationException e) {
			throw new RuntimeException(e.getMessage(), e);
		} catch (JsonMappingException e) {
			throw new RuntimeException(e.getMessage(), e);
		} catch (IOException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
	}

	/**
	 * 构造类型
	 * 
	 * @param type
	 *            类型
	 * @return 类型
	 */
	public static JavaType constructType(Type type) {
		Assert.notNull(type);

		return TypeFactory.defaultInstance().constructType(type);
	}

	/**
	 * 构造类型
	 * 
	 * @param typeReference
	 *            类型
	 * @return 类型
	 */
	public static JavaType constructType(TypeReference<?> typeReference) {
		Assert.notNull(typeReference);

		return TypeFactory.defaultInstance().constructType(typeReference);
	}
}
